package network

import (
	"fmt"
	"io"
	"net"
	"strconv"
	"strings"
	"time"
	"crypto/tls"
)

type TcpClient struct {
	Name string
	Host string
	Port int
	IsHttps bool
	Conn net.Conn
	TlsConn *tls.Conn
	SendFailNum int
}

//初始化TCP连接
func (tc *TcpClient) Init() bool {
	tc.Host = strings.ToLower(tc.Host)
	tc.IsHttps = strings.HasPrefix(tc.Host,"https")
	if tc.IsHttps {
		tc.Host = strings.Replace(tc.Host,"https://","",1)
	} else {
		tc.Host = strings.Replace(tc.Host,"http://","",1)
	}
	return tc.initConn()
}
func (tc *TcpClient) initConn() bool {
	if tc.IsHttps {
		//https连接
		conn, err := tls.Dial("tcp", tc.Host+":"+strconv.Itoa(tc.Port),nil)
		if err != nil {
			fmt.Println(tc.Name+"创建网络连接失败：", err)
			return false
		}
		tc.TlsConn = conn
	} else {
		//http连接
		conn, err := net.Dial("tcp", tc.Host+":"+strconv.Itoa(tc.Port))
		if err != nil {
			fmt.Println(tc.Name+"创建网络连接失败：", err)
			return false
		}
		tc.Conn = conn
	}
	tc.SendFailNum = 0
	return true
}


//发起HTTP请求
func (tc *TcpClient) SendHttpReq(data []byte, showr int) {
	//连接状态检查
	if tc.TlsConn == nil && tc.Conn == nil {
		fmt.Println(fmt.Sprintf("%s 连接未初始化或已被关闭.", tc.Name))
		fmt.Println(fmt.Sprintf("%s 开始重连...", tc.Name))
		OK := tc.initConn()
		if !OK {
			fmt.Println(fmt.Sprintf("%s 开始重连失败！！！", tc.Name))
			return
		} else {
			fmt.Println(fmt.Sprintf("%s 开始重连成功.", tc.Name))
		}
	}

	//发送请求数据
	if tc.Conn != nil {
		tc.Conn.SetWriteDeadline(time.Now().Add(time.Second * 30)) //写超时时间30秒
		ns, err := tc.Conn.Write(data)
		if err != nil {
			fmt.Println(fmt.Sprintf("%s 发送http请求失败：", tc.Name), err)
			tc.SendFailNum += 1
			if tc.SendFailNum >= 3 {
				//失败3次断开连接，重新连接
				tc.Conn.Close()
				tc.Conn = nil
			}
			return
		} else {
			fmt.Println(fmt.Sprintf("%s 发送http请求成功，数据包 %d 字节", tc.Name, ns))
		}
	} else {
		tc.TlsConn.SetWriteDeadline(time.Now().Add(time.Second * 30)) //写超时时间30秒
		ns, err := tc.TlsConn.Write(data)
		if err != nil {
			fmt.Println(fmt.Sprintf("%s 发送http请求失败：", tc.Name), err)
			tc.SendFailNum += 1
			if tc.SendFailNum >= 3 {
				//失败3次断开连接，重新连接
				tc.Conn.Close()
				tc.Conn = nil
			}
			return
		} else {
			fmt.Println(fmt.Sprintf("%s 发送http请求成功，数据包 %d 字节", tc.Name, ns))
		}
	}


	//读取响应数据
	var allData []byte
	if tc.Conn != nil {
		for {
			var data = make([]byte, 100)
			tc.Conn.SetReadDeadline(time.Now().Add(time.Second * 30)) //读取超时时间30秒
			n, err := tc.Conn.Read(data)
			if n > 0 {
				allData = append(allData, data...)
				if n < 100 {
					//读到尾部
					break
				}
			}
			if err != nil {
				if err == io.EOF {
					fmt.Println(fmt.Sprintf("%s 网络连接断开!!!", tc.Name), err)
					tc.Conn.Close()
					tc.Conn = nil
				} else {
					fmt.Println("读取响应结果失败：", err)
				}
				break
			}
		}
	} else {
		for {
			var data = make([]byte, 100)
			tc.TlsConn.SetReadDeadline(time.Now().Add(time.Second * 30)) //读取超时时间30秒
			n, err := tc.TlsConn.Read(data)
			if n > 0 {
				allData = append(allData, data...)
				if n < 100 {
					//读到尾部
					break
				}
			}
			if err != nil {
				if err == io.EOF {
					fmt.Println(fmt.Sprintf("%s 网络连接断开!!!", tc.Name), err)
					tc.TlsConn.Close()
					tc.TlsConn = nil
				} else {
					fmt.Println("读取响应结果失败：", err)
				}
				break
			}
		}
	}

	//打印响应内容
	if len(allData) > 0 {
		tc.PrintHttpResp(allData, showr)
	}
}

//打印HTTP响应结果
func (tc *TcpClient) PrintHttpResp(resp []byte, showr int) {
	if showr == 0 {
		//不打印
		return
	} else if showr == 1 {
		//打印响应状态
		//1.读取第一行数据
		var line []byte
		for _, d := range resp {
			line = append(line, d)
			if d == '\n' {
				break
			}
		}
		//2.解析第一行内容并打印
		if len(line) > 0 {
			sLine := string(line)
			cl := strings.Split(sLine, " ")
			if len(cl) == 3 {
				fmt.Println(fmt.Sprintf("%s 响应结果状态：%s", tc.Name, cl[1]))
			}
		}
	} else if showr == 2 {
		//打印全部响应内容
		fmt.Println(fmt.Sprintf("%s 响应结果内容：", tc.Name))
		fmt.Println(string(resp))
	}
}
